/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.google.code.peersim.pastry.protocol;

import java.util.UUID;

/**
 * Message used to discover the most suitable node for owning a resource in the
 * Pastry network. The key stores the resource id.
 *
 * @author frusso
 * @version 0.1
 * @since 0.1
 */
public class SendResource<T> extends PastryMessage {

  private PastryResource<T> resource;

  /**
   * Constructor.
   *
   * @param src The sender
   * @param dst The received
   * @param res The resource
   */
  SendResource(PastryNode src, PastryNode dst, PastryResource<T> res) {
    super.setType(Type.SEND_RESOURCE);
    super.setKey(res.getResourceId());
    super.setOrignator(src);
    super.setSender(src);
    super.setDestination(dst);
    this.resource = res;
  }

  /**
   * Returns the resource.
   *
   * @return The resource
   */
  public PastryResource<T> getResource() {
    return resource;
  }

  /**
   * Creates a brand new message instance for forwarding purposes.
   * The number of hops is inherited from the current one.
   *
   * @param nextStep The next destination
   * @return The new message
   */
  SendResource forward(PastryNode nextStep) {
    SendResource f = new SendResource(this.getSrc(), nextStep, resource);
    f.setOrignator(this.getOriginalSender());
    f.setHops(this.getHops());
    return f;
  }

  /**
   * Creates an ack message stating that the optimal node for storing the resource
   * has been found. The number of hops is inherited from the current one.
   *
   * @return The positive ack
   */
  SendResourceAck ackFinalNode() {
    SendResourceAck ack = new SendResourceAck(this.getDst(), this.getOriginalSender(), this.resource, this.getId(), null);
    ack.setOrignator(this.getOriginalSender());
    ack.setHops(this.getHops());
    return ack;
  }

  /**
   * Creates an ack message stating that the optimal node for storing the resource
   * has not been found. The number of hops is inherited from the current one.
   * This message also suggests the next node that should be contacted.
   *
   * @return The negative ack
   */
  SendResourceAck ackNonFinalNode(PastryId nextStep) {
    SendResourceAck ack = new SendResourceAck(this.getDst(), this.getOriginalSender(), this.resource, this.getId(), nextStep);
    ack.setOrignator(this.getOriginalSender());
    ack.setHops(this.getHops());
    return ack;
  }

  /**
   * A message sent to answer to {@link SendResource} messages. The correlation id serves
   * the purpose of associating an instance of this class with its {@link SendResource}
   * message. If the {@link SendResourceAck#getNextHop()} returns a non {@code null} value
   * this means the request has to be forwarded to the suggested node, otherwise the
   * optimal owner has been found and is the message sender.
   *
   * @author frusso
   * @version 0.1
   * @since 0.1
   */
  static class SendResourceAck extends SendResource {

    private UUID correlationId;
    private PastryId nextHop;

    /**
     * Constructor.
     *
     * @param src The sender
     * @param dst The destination
     * @param res The resource
     * @param corrId The correlation id
     * @param nextStep The next step
     */
    private SendResourceAck(PastryNode src, PastryNode dst, PastryResource<?> res, UUID corrId, PastryId nextStep) {
      super(src, dst, res);
      super.setType(Type.SEND_RESOURCE_ACK);
      correlationId = corrId;
      nextHop = nextStep;
    }

    /**
     * Returns the next step, or {@code null}.
     * @return The next step if any
     */
    public PastryId getNextHop() {
      return nextHop;
    }

    /**
     * Returns the correlation id.
     * @return The correlation id
     */
    public UUID getCorrelationId() {
      return correlationId;
    }
  }
}